package messages;

import java.security.PrivateKey;
import java.security.PublicKey;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import security.Hash;
import security.crypto.AssimEncryption;
import utils.Serialization;
import utils.XmlSerializationUtils;

public class MessageSignature implements Convertible{

	private static final long serialVersionUID = 1L;
	
	private String _endpointId;
	private String _remoteEndpointId;
	private String _currentTimestamp;
	private String _messageHash;	
	
	private String _cipheredSignature;
	
	public MessageSignature(){}
	
	public MessageSignature(String endpointId, String remoteEndpointId, String messageHash, PrivateKey privateKey){
		_endpointId = endpointId;
		_remoteEndpointId = remoteEndpointId;
		_messageHash = messageHash;
		_currentTimestamp = (new Long(System.currentTimeMillis())).toString();
		
		_cipheredSignature = signMessage(privateKey);
	}
	
	public String getTimestamp() {
		return _currentTimestamp;
	}

	private String signMessage(PrivateKey privateKey) {
		String serializedSignature = Serialization.SerializeAsXml(this);
		String hashedSignature = Hash.getStringHash(serializedSignature);
		
		return AssimEncryption.signHash(hashedSignature, privateKey);
	}
	
	public boolean validateSignature(String hashedObject, String remoteEndpointId, String endpointId, String lastReceivedMessageTS, PublicKey publicKey) {
		if(!remoteEndpointId.equals(_endpointId))
			return false;
		
		if(!endpointId.equals(_remoteEndpointId))
			return false;
		
		if(!_messageHash.equals(hashedObject))
			return false;
		
		Long longMessageTs = Long.parseLong(_currentTimestamp);
		Long lastMessageTs = Long.parseLong(lastReceivedMessageTS);
		if(longMessageTs < lastMessageTs)
			return false;
		
		String cipheredSignature = _cipheredSignature;
		_cipheredSignature = null;
		
		String serializedSignature = Serialization.SerializeAsXml(this);
		String signatureHash = Hash.getStringHash(serializedSignature);
		
		return AssimEncryption.validateSignature(signatureHash, cipheredSignature, publicKey);
	}

	public Element convertToCanonic(Document doc) {
		Element el = doc.createElement("MessageSignature");

		if (_endpointId != null) {
			Element childEl = doc.createElement("EndpointId");
			childEl.setTextContent(_endpointId);
			el.appendChild(childEl);
		}
		
		if (_remoteEndpointId != null) {
			Element childEl = doc.createElement("RemoteEndpointId");
			childEl.setTextContent(_remoteEndpointId);
			el.appendChild(childEl);
		}
		
		if (_currentTimestamp != null) {
			Element childEl = doc.createElement("CurrentTimestamp");
			childEl.setTextContent(_currentTimestamp);
			el.appendChild(childEl);
		}
		
		if (_messageHash != null) {
			Element childEl = doc.createElement("MessageHash");
			childEl.setTextContent(_messageHash);
			el.appendChild(childEl);
		}
		
		if (_cipheredSignature != null) {
			Element childEl = doc.createElement("CipheredSignature");
			childEl.setTextContent(_cipheredSignature);
			el.appendChild(childEl);
		}
		
		return el;
	}

	public Object convertFromCanonic(Element el) {
		this._endpointId = XmlSerializationUtils.getTextValue(el, "EndpointId");
		this._remoteEndpointId = XmlSerializationUtils.getTextValue(el, "RemoteEndpointId");
		this._currentTimestamp= XmlSerializationUtils.getTextValue(el, "CurrentTimestamp");
		this._messageHash = XmlSerializationUtils.getTextValue(el, "MessageHash");
		this._cipheredSignature = XmlSerializationUtils.getTextValue(el, "CipheredSignature");
		return this;
	}
}
